package interval

import (
	"context"
	"gitee.com/ymofen/gobase"
	"sync"
	"time"
)

// 为什么 sync.Map调用了 Delete(key)方法之后，仍然可能对 key 保持引用，导致 key 对应的对象无法被垃圾回收（GC）
// 不推荐使用
type IntervalSyncMapEngine struct {
	lst sync.Map
}

func (this *IntervalSyncMapEngine) exec(itm *intvIem, nowUnix int64) {

	if !itm.busyFlag.CompareAndSwap(0, 1) {
		return
	}

	if nowUnix-itm.lastTime < itm.interval {
		itm.busyFlag.Store(0)
		return
	}

	go gobase.GoRun(func() {
		defer func() {
			itm.busyFlag.Store(0)
			itm.lastTime = nowUnix
		}()
		itm.fn()

	})
}

func (this *IntervalSyncMapEngine) OpenInterval(id interface{}, interval time.Duration, fn func()) (err error) {
	if itm0, ok := this.lst.LoadOrStore(id, &intvIem{interval: int64(interval.Seconds()), lastTime: 0, fn: fn}); ok {
		itm := itm0.(*intvIem)
		itm.fn = fn
		itm.interval = int64(interval.Seconds())
	}
	return
}

func (this *IntervalSyncMapEngine) Open(ctx context.Context) {
	gobase.RunContextAndInterval(ctx, time.Millisecond*500, func() {
		nowUnix := time.Now().Unix()
		this.lst.Range(func(key, value interface{}) bool {
			this.exec(value.(*intvIem), nowUnix)
			return true
		})
	})
}

func (this *IntervalSyncMapEngine) CloseInterval(id interface{}) error {
	this.lst.Delete(id)
	return nil
}

func NewIntervalSyncMapEngine() *IntervalSyncMapEngine {
	def := &IntervalSyncMapEngine{}
	go def.Open(context.Background())
	return def
}
